﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;

namespace AOC19NET.Classes {
	/// <summary>
	/// Offers some helper functions to work with colors.
	/// </summary>
	class ColorHelper {
		#region METHODS
		/// <summary>
		/// Compose the HEX string for the given color.
		/// </summary>
		/// <param name="_InputColor">The color to represent.</param>
		/// <param name="_bUseAlpha">Shall the alpha value be included in the HEX representation?.</param>
		/// <returns>String representing the HEX value of the input color in the format RRGGBB or RRGGBBAA.</returns>
		public static String RGBToHex(Color _InputColor, bool _bUseAlpha) {
			byte[] vRGB;
			if(_bUseAlpha) {
				vRGB = new byte[4];
				vRGB[0] = _InputColor.R;
				vRGB[1] = _InputColor.G;
				vRGB[2] = _InputColor.B;
				vRGB[3] = _InputColor.A;
			} else {
				vRGB = new byte[3];
				vRGB[0] = _InputColor.R;
				vRGB[1] = _InputColor.G;
				vRGB[2] = _InputColor.B;
			}

			String sHex = BitConverter.ToString(vRGB);
			return sHex.Replace("-", "");
		}

		/// <summary>
		/// Convert a string containing an RGB value in HEX to its equivalent color.
		/// </summary>
		/// <param name="_sHex">The string containing the HEX value in the form RRGGBB/RRGGBBAA</param>
		/// <returns>The equivalent color if the input string is valid. Black otherwise.</returns>
		public static Color HexToRGB(String _sHex) {
			int iNumChars = _sHex.Length;
			if(iNumChars != 6 || iNumChars != 8) {
				// The input array is not valid.
				return Colors.Black;
			}

			// Get the bytes
			byte[] vRGB = new byte[iNumChars];
			for(int i = 0; i < iNumChars; i += 2) {
				vRGB[i/2] = Convert.ToByte(_sHex.Substring(i, 2), 16);
			}

			// Return the color
			Color NewColor;
			if(iNumChars == 6) {
				NewColor = Color.FromRgb(vRGB[0], vRGB[1], vRGB[2]);
			} else {
				NewColor = Color.FromArgb(vRGB[3], vRGB[0], vRGB[1], vRGB[2]);
			}
			return NewColor;
		}

		/// <summary>
		/// Performs the linear interpolation between _Color1 and _Color2.
		/// </summary>
		/// <param name="_Color1">First color in the gradient.</param>
		/// <param name="_Color2">Second color in the gradient.</param>
		/// <param name="_fDelta">Point at which interpolate [0..1].</param>
		/// <returns>The value of the interpolation between _Color1 and _Color2 at the point _dDelta.</returns>
		public static Color Interpolate(Color _Color1, Color _Color2, float _fDelta) {
			Color NewColor = _Color1;
			NewColor.ScR = _Color1.ScR * (1.0f - _fDelta) + _Color2.ScR * _fDelta;
			NewColor.ScG = _Color1.ScG * (1.0f - _fDelta) + _Color2.ScG * _fDelta;
			NewColor.ScB = _Color1.ScB * (1.0f - _fDelta) + _Color2.ScB * _fDelta;

			return NewColor;
		}

		/// <summary>
		/// Obtain a tinted color based on the _BaseColor.
		/// </summary>
		/// <param name="_BaseColor">The base color.</param>
		/// <param name="_fTintLevel">Tint level. Float value within the range [0..1] where 0.0f is Black, 0.5f is the original base color and 1.0f is white.</param>
		/// <returns>The tinted _BaseColor.</returns>
		public static Color Tint(Color _BaseColor, float _fTintLevel) {
			// Clamp Tint Level
			if(_fTintLevel > 1.0f) _fTintLevel = 1.0f;
			if(_fTintLevel < 0.0f) _fTintLevel = 0.0f;

			// Shadow or tint?
			Color NewColor = _BaseColor;
			if(_fTintLevel <= 0.5f) {
				NewColor = Interpolate(Colors.Black, _BaseColor, _fTintLevel * 2.0f);
			} else {
				NewColor = Interpolate(_BaseColor, Colors.White, (_fTintLevel - 0.5f) * 2.0f);
			}

			return NewColor;
		}
		#endregion
	}
}
